﻿using NiceControls;
using SimpleTerminal.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Timers;
using System.Windows.Forms;
using Win32;
using static SimpleTerminal.TerminalControl.Line;
using static SimpleTerminal.TerminalControl.TerminalContainer;

namespace SimpleTerminal.TerminalControl
{
    public partial class Terminal : Control, ISupportInitialize
    {


        protected Size fontSize = new Size(0, 0);

        private static readonly object _drawLock = new object();

        //  private readonly Graphics graphics;  //主画布
        // protected Graphics bufferGraphics; //缓冲区画布，用于实现双缓冲
        protected BufferedGraphics myBuffer; //缓冲
        protected StringFormat sf;//字体样式
        protected readonly SolidBrush foreSolidBrush;
        protected readonly SolidBrush backSolidBrush;
        private bool cursorVisible = true; //是否显示光标
        private bool uiHangUp = false;
        protected readonly TerminalFont terminalFont;
        // Bitmap bitmapBuffer;
        // Graphics bitmapGraphics;

        private bool isDECCKM = false;//ESC[替换成ESCO序列


        private readonly Analyzer analyzer;


        protected int displayColumns = 0;
        protected int displayRows = 0;
        protected bool IsFocused = false;





        public delegate void MouseReportHandler(int keycode, int x, int y);
        public delegate void TerminalEventdHandler(Terminal terminal);

        public event MouseReportHandler OnMouseReport;
        public event TerminalEventdHandler TerminalSizeChanged;
        public event TerminalEventdHandler TerminalOnLoaded;
        //public event TerminalEventdHandler GotFocus;

        protected readonly System.Timers.Timer mouseMoveLeaveTimer = new System.Timers.Timer();
        protected readonly System.Timers.Timer mouseClickTimer = new System.Timers.Timer();

        protected bool mouseReport = false;
        //readonly Thread analyzerThread = null;

        bool Initialize = false;
        TLog log;
        bool mouseDown = false;
        Point mousePoint = new Point();
        int mouseDownColumns = 0;
        int mouseDownRows = 0;
        protected readonly SelectRange selectRegion = new SelectRange();
        protected Point point = new Point();
        protected bool mouseHasMove = false;
        protected bool onMouseDoubleClick = false;
        protected bool CtrlDown = false;//标记Ctrl按键是否被按下
        protected Graphics graphics;
        protected Graphics bufferedGraphics;
        protected List<Keyword> keywords;

        [Category("自定义属性")]
        [Description("光标背景色")]
        [Browsable(true)]
        public Color CursorBackColor { get; set; }


        [Category("自定义属性")]
        [Description("光标选中字体颜色")]
        [Browsable(true)]
        public Color CursorTextColor { get; set; }

        [Localizable(false)]
        [Browsable(false)]
        public List<Keyword> Keywords
        {
            get
            {
                return keywords;
            }
            set
            {
                keywords = value;
                container?.InvalidAbs(screenLineStart, container.Height);
                InvalidatePaint();
            }
        }

        protected virtual void _InitializeComponent()
        {
            InitializeComponent();
            scrollBar.Cursor = Cursors.Default;
            Controls.Add(scrollBar);


        }

        public Terminal()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.Opaque, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            //SetStyle(ControlStyles.SupportsTransparentBackColor, false);
            //SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            graphics = CreateGraphics();

            _InitializeComponent();
            InitializeRows();


            sf = StringFormat.GenericTypographic;
            //sf = StringFormat.GenericDefault;

            //设置笔刷
            foreSolidBrush = new SolidBrush(ForeColor);
            backSolidBrush = new SolidBrush(BackColor);
            terminalFont = new TerminalFont(Font);


            //用于鼠标选择超出边界移动滚动条的计时器
            mouseMoveLeaveTimer.Interval = 20;
            mouseMoveLeaveTimer.Elapsed += new ElapsedEventHandler(MouseMoveLeaveTimer); // 定义回调
            mouseMoveLeaveTimer.AutoReset = true;
            mouseMoveLeaveTimer.Enabled = false;

            /*
             * 用于实现三次点击选择整行的计时器
             * 500毫秒后清除双击标记
             */
            mouseClickTimer.Interval = 500;
            mouseClickTimer.Elapsed += new ElapsedEventHandler(delegate
            {
                onMouseDoubleClick = false;
            });
            mouseClickTimer.AutoReset = false;
            mouseClickTimer.Enabled = false;
            analyzer = new Analyzer(this);

            InitImageBackground();
        }

        ~Terminal()
        {
            Close();
            Dispose(false);
        }
        bool Closed = false;
        public void Close()
        {
            if (Closed)
                return;
            Closed = true;
            try
            {
                /*
                if (analyzerThread.IsAlive)
                {
                    analyzerThread.Abort();
                }*/
                myBuffer.Dispose();
                bufferedGraphics.Dispose();

                backSolidBrush.Dispose();
                foreSolidBrush.Dispose();
                //container.ClearScrollBack();
                terminalFont.Dispose();



                if (log != null)
                {
                    log.Close();
                }
            }
            catch (Exception)
            {

            }
            Dispose(true);
        }
        //  protected override o

        public void Refresh(bool force)
        {
            if (force)
                container?.InvalidAbs(screenLineStart, container.Height);
            InvalidatePaint();
        }
        public bool MouseReport
        {
            set
            {
                Invoke((EventHandler)delegate
                {
                    if (value)
                        Cursor = Cursors.Default;
                    else
                        Cursor = Cursors.IBeam;
                });

                mouseReport = value;
            }
        }

        /// <summary>
        /// 滚动条滚动时候触发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void VScrollBar_Scroll(object sender, NScrollBar.ScrollEventArgs e)
        {
            ScrollTo(e.NewValue);
            InvalidatePaint();
        }



        public bool LogStarting
        {
            get
            {
                return log == null;
            }
        }

        public string LogPath
        {
            get;
            set;
        }

        public void StopLog()
        {
            if (log != null)
                log.Close();
            container.LogWrite = false;
            log = null;
        }
        public void StartLog(string name)
        {

            SaveFileDialog saveFileDialog = new SaveFileDialog();

            saveFileDialog.FileName = name + "_log.txt";

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    log = new TLog();
                    log.Open(saveFileDialog.FileName);
                    container.LogInstance = log;
                    container.LogWrite = true;
                    LogPath = saveFileDialog.FileName;
                    //Console.WriteLine("日志位置"+ LogPath);
                }
                catch (Exception)
                {
                    log = null;
                    throw;
                }
            }
            saveFileDialog.Dispose();
        }




        /// <summary>
        /// 更新界面
        /// </summary>
        public void UpdateUi()
        {
            if (ScreenLineStart != container.ConsoleOffset)
            {
                ScrollTo(container.ConsoleOffset);
                UpdateScrollBar();
            }
            else if (container.ScreenOffset > 0)
            {
                ScrollTo(container.ConsoleOffset - container.ScreenOffset,
                    container.ConsoleOffset);
            }

            InvalidatePaint();

            container.ScreenOffset = 0;
        }

        protected bool half = false;


        /// <summary>
        /// 绘制单个字符，并且填充背景色
        /// </summary>
        /// <param name="character"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="inverse"></param>
        /// <returns></returns>
        protected virtual int RenderCharacter(Graphics graphics, Character character, int x, int y, bool inverse)
        {
            int oldX = x;
            int w = fontSize.Width;
            bool force = false;

            if (character.TestMask(CharacterMask.Half1))
            {
                half = true;
                goto End;
            }
            else if (character.TestMask(CharacterMask.Half2))
            {
                if (!half)
                {
                    goto End;
                }
                else
                {
                    half = false;
                    w += fontSize.Width;
                    x -= fontSize.Width;
                }
            }
            else
            {
                half = false;
            }

            /**
             * 判断是否需要反色，通常是因为处在选区当中
             */
            if (inverse)
            {
                foreSolidBrush.Color = character.Bg.color;
                backSolidBrush.Color = character.Fg.color;
            }
            else
            {
                backSolidBrush.Color = character.Bg.color;
                foreSolidBrush.Color = character.Fg.color;
            }

            /**
             * 如果处于选择区域内，则判断当前背景画笔颜色是否等于默认的前景色
             * 否则判断当前背景画笔颜色是否等于默认等景色
             * 以上都不是才需要绘制背景
             */
            if ((inverse && backSolidBrush.Color != container.defaultForeground.color) ||
                (!inverse && backSolidBrush.Color != container.defaultBackground.color) || force)
            {
                graphics.FillRectangle(backSolidBrush, x, y, w, fontSize.Height);
            }
            if (!character.TestMask(CharacterMask.Empty))
            {
                Font font = character.TestMask(CharacterMask.Underline) ? terminalFont.Underline : terminalFont.Regular;
                graphics.DrawString(character.c.ToString(), font, foreSolidBrush, x, y + 1, sf);
            }

        End:
            oldX += fontSize.Width;

            return oldX;
        }
        protected Image ImageBg;
        protected virtual void InitImageBackground()
        {
           // ImageBg = Image.FromFile("testbg.jpg");
            
            //Image image = Image.FromFile("testbg.jpg");
            //  Bitmap bitmap = Bitmap.;
        }

        /// <summary>
        /// 绘制背景色
        /// </summary>
        /// <param name="index"></param>
        /// <param name="offset"></param>
        protected virtual void RenderLineBg(Graphics graphics, int index, int offset)
        {
            graphics.CompositingMode = CompositingMode.SourceCopy;

            bool enable = selectRegion.Enable;
            int selectRegionStartX = selectRegion.StartX;
            int selectRegionEndX = selectRegion.EndX;
            int selectRegionStartY = selectRegion.StartY;
            int selectRegionEndY = selectRegion.EndY;

            backSolidBrush.Color = BackColor;
            foreSolidBrush.Color = ForeColor;

            if (enable && index >= selectRegionStartY && index <= selectRegionEndY)
            {

                graphics.FillRectangle(foreSolidBrush, GetTextOffsetLeft(), offset,
                    displayColumns * fontSize.Width, fontSize.Height);

                if (index == selectRegionStartY && selectRegionStartX > 0)
                {
                    graphics.FillRectangle(backSolidBrush, GetTextOffsetLeft(),
                                    offset,
                                    selectRegionStartX * fontSize.Width,
                                    fontSize.Height);

                }
                if (index == selectRegionEndY && selectRegionEndX < displayColumns - 1)
                {
                    graphics.FillRectangle(backSolidBrush,
                        GetTextOffsetLeft() + (selectRegionEndX + 1) * fontSize.Width,
                            offset,
                            (displayColumns - selectRegionEndX - 1) * fontSize.Width,
                            fontSize.Height);
                }
            }
            else
            {
                graphics.FillRectangle(backSolidBrush, 0, offset,
                   Width, fontSize.Height);
                // bufferGraphics.FillRectangle(backSolidBrush, all);
            }
            /*
            float[][] ptsArray =
                {
                    new float[]{1,0,0,0,0},
                    new float[]{0,1,0,0,0},
                    new float[]{0,0,1,0,0},
                    new float[]{0,0,0,0.2f,0},
                    new float[]{0,0,0,0,1}
                };
            ColorMatrix clrMatrix = new ColorMatrix(ptsArray);
            ImageAttributes imgAttributes = new ImageAttributes();
            imgAttributes.SetColorMatrix(clrMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
          

             float tb = offset * (ImageBg.Height / Height);
            float hb = fontSize.Height * (ImageBg.Height / Height);
            float wb = Width * (ImageBg.Width / Width);
            graphics.DrawImage(ImageBg,
                new Rectangle(0, offset, Width, fontSize.Height),
                0, tb, wb, hb,
                GraphicsUnit.Pixel,
                imgAttributes
                );*/

            graphics.CompositingMode = CompositingMode.SourceOver;
          
        }

        /// <summary>
        /// 绘制光标
        /// </summary>
        protected virtual void RenderCursor(Graphics graphics)
        {
            /* 显示光标 */
            if (ShowCursor())
            {
                Character character = container.CurrentLine().GetCharacter(container.CursorIndex);
                int x = GetTextOffsetLeft() + container.CursorIndex * fontSize.Width;
                int y = GetTextOffsetTop() + (container.CurrentLineAdsIndex - screenLineStart) * fontSize.Height;
                int w = fontSize.Width;
                if (character.TestMask(CharacterMask.Half1))
                {
                    w *= 2;
                }
                // User32.SetCaretPos(x,y);
                //User32.ShowCaret(Handle);
                // /*
                Font font = character.TestMask(CharacterMask.Underline) ? terminalFont.Underline : terminalFont.Regular;

                foreSolidBrush.Color = CursorTextColor;

                if (!IsFocused && character.TestMask(CharacterMask.Empty))
                {
                    backSolidBrush.Color = BackColor;
                    graphics.FillRectangle(backSolidBrush, x, y, w, fontSize.Height);
                    using (Pen pen = new Pen(CursorBackColor))
                    {
                        graphics.DrawRectangle(pen, x, y, w - 1, fontSize.Height - 1);
                    }
                }
                else
                {
                    backSolidBrush.Color = CursorBackColor;
                    graphics.FillRectangle(backSolidBrush, x, y, w, fontSize.Height);//填充这个矩形
                }
                graphics.DrawString(character.c.ToString(), font, foreSolidBrush, x + 1, y, sf);
                //*/
            }
            else
            {
                //User32.HideCaret(Handle);
            }

        }

        int scrollingLines = 0;
        protected virtual void DoScroll(Graphics graphics, int scrollingLines)
        {

            int rows = container.Height;
            /**
             * 由原来的Bitmap间接复制改成BitBlt复制后
             * 复制时间由1-2ms减少为0.2ms左右
             * 性能提升明显！
             * */
            if (Math.Abs(scrollingLines) >= rows)
            {
                container.InvalidAbs(screenLineStart, rows);
            }
            else if (scrollingLines > 0)
            {
                int recTop = GetTextOffsetTop() + scrollingLines * fontSize.Height;
                int recHeight = (displayRows - scrollingLines) * fontSize.Height;

                IntPtr hdc = graphics.GetHdc();
                Gdi32.BitBlt(hdc, 0, GetTextOffsetTop(), Width, recHeight,
                    hdc, 0, recTop, CopyPixelOperation.SourceCopy);
                graphics.ReleaseHdc();
                container.InvalidAbs(screenLineStart + rows - scrollingLines, scrollingLines);
            }
            else if (scrollingLines < 0)
            {
                scrollingLines = -scrollingLines;

                int destY = GetTextOffsetTop() + scrollingLines * fontSize.Height;
                int destHeight = (displayRows - scrollingLines) * fontSize.Height;

                IntPtr hdc = graphics.GetHdc();

                Gdi32.BitBlt(hdc, 0, destY, Width, destHeight,
                    hdc, 0, GetTextOffsetTop(), CopyPixelOperation.SourceCopy);
                graphics.ReleaseHdc();
                container.InvalidAbs(screenLineStart, scrollingLines);
            }
        }

        public virtual void DoPaint(Graphics graphics)
        {
            bool forcePaint = false;
            //尺寸如果发生了改变则需要强制更新全部
            if (sizeChanged)
            {
                sizeChanged = false;
                forcePaint = true;
                //  UpdateTerScrollBar();
            }
            //如果内容有滚动则调用bitblt方法进行快速内容滚动
            else if (scrollingLines != 0)
            {
                DoScroll(graphics, scrollingLines);
                // UpdateTerScrollBar();
                scrollingLines = 0;
            }
            if (needUpdateScrollBar)
            {
                UpdateTerScrollBar();
                needUpdateScrollBar = false;
            }

            int lineOffset = GetTextOffsetTop();
            int paintStart;
            int paintEnd;
            //int maxPaintRows = displayRows;
            /*
            * 如果是首次绘制则绘制全屏，避免出现旧的图像销毁而新的
            * 只更新了一部分的情况出现
            */ 

            paintStart = screenLineStart;
            paintEnd = paintStart + Math.Min(displayRows, container.Height);


            //Log.Debug("PaintGraphics", "start:" + paintStart + " end:" + paintEnd + " count:" + container.Count);

            // lineOffset += fontSize.Height;
            // bufferGraphics.CompositingMode = CompositingMode.SourceOver;
            for (int i = paintStart; i < paintEnd; i++)
            {
                Line lineNode = container[i];

                /** 
                 * 检测 当前行是否被标记为无效亦或者是强制更新
                 */
                if (lineNode.State != CommonDefine.PAINT_INVALID && !forcePaint)
                    goto PaintLineDone;
                int offset = GetTextOffsetLeft();

                half = false;
                bool inverse = selectRegion.Enable && (i > selectRegion.StartY && i < selectRegion.EndY);

                RenderLineBg(graphics, i, lineOffset);
                //Console.WriteLine("更新第"+i+"行");
                /**
                 *高亮显示特定的关键词
                 */
                string line = lineNode.ToString();

                foreach (Keyword keyword in Keywords)
                {                
                    int pos = 0;

                    while (true)
                    {
                        int ret;
                        int len;
                        if (!keyword.Regular)
                        {
                            ret = line.IndexOf(
                                keyword.Pattern,
                                pos,
                                keyword.CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
                            len = keyword.Pattern.Length;
                            if (ret == -1)
                            {
                                break;
                            }
                        }
                        else
                        {
                            Match match = Regex.Match(
                                line.Substring(pos),
                                @keyword.Pattern,
                                keyword.CaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase
                                );
                            if (!match.Success)
                                break;
                            ret = pos + match.Index;
                            len = match.Length;
                        }


                        pos = ret + len;

                        for (int j = ret; j < ret + len; j++)
                        {

                            if (keyword.Scheme == 0)
                            {
                                lineNode[j].bg = TerminalColor.GetColor(1);
                                lineNode[j].fg = TerminalColor.GetColor(7);
                            }
                            else
                            {
                                lineNode[j].bg = container.defaultBackground;
                                lineNode[j].fg = TerminalColor.GetLighColor(1);
                            }
                        }
                        if (pos >= line.Length)
                            break;
                    }
                }



                /** 
                 * 使用GDI+逐个绘制字符，每个字符都需要进行ToString操作，
                 * 不知道这样会不会带来性能的损失，但是却没有其他更好的办法
                 */
                for (int j = 0; j < displayColumns; j++)
                {
                    Character character = lineNode.GetCharacter(j);
                    if (selectRegion.Enable)
                    {
                        //如果选择的行在一行内
                        if (i == selectRegion.StartY &&
                            selectRegion.StartY == selectRegion.EndY)
                            inverse = (selectRegion.StartX <= j && j <= selectRegion.EndX);
                        else if (i == selectRegion.StartY)
                            inverse = (j >= selectRegion.StartX);
                        else if (i == selectRegion.EndY)
                            inverse = (j <= selectRegion.EndX);
                    }
                    offset = RenderCharacter(graphics, character, offset, lineOffset, inverse);
                }
                lineNode.State = CommonDefine.PAINT_DONE;

            PaintLineDone:
                //更新行高偏移
                lineOffset += fontSize.Height;
            }


            //bufferGraphics.CompositingMode = CompositingMode.SourceCopy;
            //watch.Stop();
            ///   var useTime = (double)watch.Elapsed.TotalMilliseconds;
            //Log.Debug("Terminal", "Paint " + useTime);


            RenderCursor(graphics);

            myBuffer.Render();
        }


        private void InvalidatePaint()
        {
            if (Initialize)
                return;
            Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics graphics = bufferedGraphics;
            graphics.PixelOffsetMode = PixelOffsetMode.Default;
            graphics.SmoothingMode = SmoothingMode.Default;
            graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault;
            //e.Graphics.ClipBounds = new Rectangle(0,0,Width,Height);

            DoPaint(graphics);
        }

        protected override void WndProc(ref Message m)
        {
            /*
             switch (m.Msg)
             {
                 case User32.WM_PAINT:
                     User32.HideCaret(Handle);
                     base.WndProc(ref m);
                     User32.ShowCaret(Handle);
                     return;
             }
           //  */
            base.WndProc(ref m);
            // Console.WriteLine(m.ToString());
        }


        /// <summary>
        /// 
        /// </summary>
        private void Paint_OnSizeChanged()
        {

            if (Width == 0 || Height == 0)
                return;

            if (myBuffer != null)
            {
                bufferedGraphics.Dispose();
                myBuffer.Dispose();
            }
            // if (bitmapBuffer != null)
            // {
            ///     bitmapBuffer.Dispose();
            //     bitmapGraphics.Dispose();
            // }


            /** 
             * 每次尺寸改变的时候则重新申请画布等资源
             */
            // SendMessage(Handle, WM_SETREDRAW, 0, IntPtr.Zero);

            Rectangle rectangle = new Rectangle(0, 0, Width, Height);
            BufferedGraphicsContext GraphicsContext = BufferedGraphicsManager.Current;
            myBuffer = GraphicsContext.Allocate(graphics, rectangle);
            bufferedGraphics = myBuffer.Graphics;
            ///bufferGraphics.InterpolationMode = InterpolationMode.Default;
            bufferedGraphics.PixelOffsetMode = PixelOffsetMode.Default;
            bufferedGraphics.SmoothingMode = SmoothingMode.Default;
            bufferedGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault;

            //SendMessage(Handle, WM_SETREDRAW, 1, IntPtr.Zero);
            bufferedGraphics.Clear(BackColor);
            // bitmapBuffer = new Bitmap(Width, Height);
            // bitmapGraphics = Graphics.FromImage(bitmapBuffer);*/
            // needMeasure = true;
            OnMeasure(bufferedGraphics);
            sizeChanged = true;
        }

        bool sizeChanged = false;
        /// <summary>
        /// 
        /// </summary>
        private void OnMeasure(Graphics graphics)
        {

            terminalFont.Font(Font);

            SizeF mSizeF = graphics.MeasureString("A", terminalFont.Bold, PointF.Empty, sf);
            fontSize.Height = (int)mSizeF.Height + 2;
            fontSize.Width = (int)Math.Round(mSizeF.Width);
            //统计行列数
            displayRows = (GetWorkHeight() / fontSize.Height);
            displayColumns = (GetWorkWidth() / fontSize.Width);

            //Console.WriteLine("字体：" + mSizeF.Height + " " + mSizeF.Width);
            //Console.WriteLine("字体：" + fontSize.Height + " " + fontSize.Width);
        }

        private void OnStyleChanged()
        {
            /**
             * 清除一下背景，防止动态改变背景颜色的时候上下边距的背景不擦除
             */

            if (bufferedGraphics == null)
                return;

            bufferedGraphics.Clear(BackColor);

            OnMeasure(bufferedGraphics);
            TerminalRowsChanged();
        }

        private void TerminalRowsChanged()
        {
            if (GetDisplayRows() == 0 || GetDisplayColumns() == 0)
                return;
            container.Height = GetDisplayRows();
            container.ConsoleWidth = GetDisplayColumns();
            ScreenLineStart = container.ConsoleOffset;
            UpdateScrollBar();
            TerminalSizeChanged?.Invoke(this);
        }
        private bool needUpdateScrollBar = false;
        private void UpdateScrollBar()
        {
            //UpdateTerScrollBar();
            needUpdateScrollBar = true;
        }

        private void UpdateTerScrollBar()
        {
            if (scrollBar == null)
                return;
            if (GetDisplayRows() > 0 && container.Count > GetDisplayRows())
            {
                int offset = container.ConsoleOffset;
                int newValue = ScreenLineStart;

                scrollBar.Enabled = true;
                scrollBar.Minimum = container.Minimum;
                scrollBar.Maximum = offset + displayRows - 1;
                scrollBar.LargeChange = displayRows;
                scrollBar.Value = newValue;
            }
            else
            {
                scrollBar.Enabled = false;
            }
        }


        public bool SelectRegionState
        {
            get
            {
                return selectRegion.Enable;
            }

            set
            {
                if (!value)
                    selectRegion.Reset();
                selectRegion.Enable = value;
            }
        }

        private string GetText(int start, int end, int startx, int endx)
        {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = start; i <= end; i++)
            {
                List<Character> characters = container[i].Characters;
                int startindex = i == start ? startx : 0;
                int len = characters.Count - startindex;
                if (len > 0)
                {
                    if (i == end)
                    {
                        len = endx - startindex + 1;
                        if (len > characters.Count - startindex)
                        {
                            len = characters.Count - startindex;
                        }
                    }
                    for (int j = 0; j < len; j++)
                    {
                        Character character = (Character)characters[startindex + j];
                        if (character.TestMask(CharacterMask.Half1))
                            continue;
                        stringBuilder.Append(character.c.ToString());
                    }
                }
                stringBuilder.Append("\r\n");
            }
            return stringBuilder.ToString();
        }

        public override string Text
        {
            get
            {

                int start = 0;
                int end = container.Count - 1;
                return GetText(start, end, 0, displayColumns);

            }
        }

        public string ScreenText
        {
            get
            {

                int start = ScreenLineStart;
                int end = ScreenLineStart + Math.Min(container.Height, displayRows) - 1;
                return GetText(start, end, 0, displayColumns);

            }
        }
        /// <summary>
        /// 获取选取选中的文本
        /// </summary>
        /// <returns></returns>
        public SelectRange SelectRegion
        {
            get
            {
                return selectRegion;
            }
        }
        public string SelectRegionText
        {
            get
            {

                int start = selectRegion.StartY;
                int end = selectRegion.EndY;
                return GetText(start, end, selectRegion.StartX, selectRegion.EndX);

            }
        }

        public bool DECCKM { get => isDECCKM; set => isDECCKM = value; }

        public SolidBrush ForeSolidBrush => foreSolidBrush;

        public SolidBrush BackSolidBrush => backSolidBrush;


        protected override void OnFontChanged(EventArgs e)
        {
            base.OnFontChanged(e);
            DoStyleChanged();
        }

        protected override void OnBackColorChanged(EventArgs e)
        {
            base.OnBackColorChanged(e);
            if (container != null)
                container.SetDefaultBackground(BackColor);
            DoStyleChanged();
        }

        protected override void OnForeColorChanged(EventArgs e)
        {
            base.OnBackColorChanged(e);
            container.SetDefaultForeground(ForeColor);
            DoStyleChanged();
        }

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            base.OnPaintBackground(pevent);
            //InvalidatePaint();
            //bufferGraphics.Clear(BackColor);
            //graphics.Clear(BackColor);
            //return;
        }
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
        }

        protected void WindowSizeChanged()
        {
            TerminalRowsChanged();
            InvalidatePaint();
        }
        protected override void NotifyInvalidate(Rectangle invalidatedArea)
        {
            base.NotifyInvalidate(invalidatedArea);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            //Log.Debug("OnPaint", "OnSizeChanged"+Width +":" + Height);
            /**
            * 如果宽度为0则说明窗口进入了最小化的模式
            * 此时不进行资源重新计算，而是直接挂起布局
            * 再度恢复也不立即计算，而是复用之前的
            */
            // Form form = FindForm();
            Paint_OnSizeChanged();
            if (Width == 0 || Height == 0)
            {
                uiHangUp = true;
            }
            else
            {
                if (uiHangUp)
                    uiHangUp = false;
                else
                {
                    selectRegion.Reset();

                    WindowSizeChanged();
                    //delayAction.Debounce(200, this, WindowSizeChanged);
                }
            }
            base.OnSizeChanged(e);
        }

        protected override void OnInvalidated(InvalidateEventArgs e)
        {
            base.OnInvalidated(e);
        }



        protected override void OnParentVisibleChanged(EventArgs e)
        {
            base.OnParentVisibleChanged(e);
        }


        /// <summary>
        /// 由控件处理方向键
        /// </summary>
        /// <param name="keyData"></param>
        /// <returns></returns>
        protected override bool ProcessDialogKey(Keys keyData)
        {
            if (keyData == Keys.Tab || keyData == Keys.Up || keyData == Keys.Down ||
                keyData == Keys.Left || keyData == Keys.Right)
            {
                return false;
            }
            else
            {
                return base.ProcessDialogKey(keyData);
            }
        }

        /// <summary>
        /// 鼠标滑轮滚动时触发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);

            if (CtrlDown)
            {
                float fontp = Font.Size;
                if (e.Delta > 0 && fontp < 18)
                {
                    fontp++;
                }
                else if (e.Delta < 0 && fontp > 9)
                {
                    fontp--;
                }
                Font = new Font(Font.FontFamily, fontp, Font.Style);
            }
            else
            {
                int rows = e.Delta > 0 ? 3 : -3;
                if (scrollBar.Enabled)
                {
                    int newValue = scrollBar.Value - rows;

                    if (newValue < 0)
                        newValue = 0;
                    else if (newValue > scrollBar.Maximum - scrollBar.LargeChange + 1)
                        newValue = scrollBar.Maximum - scrollBar.LargeChange + 1;

                    ScrollTo(newValue);
                    UpdateScrollBar();
                    InvalidatePaint();
                }
            }

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnKeyDown(KeyEventArgs e)
        {

            int x = container.CursorIndex * fontSize.Width + GetTextOffsetLeft();
            int y = container.CursorLineIndex * fontSize.Height + GetTextOffsetTop();

            //调整输入法的位置 
            Imm32.SetCompositionWindow(Handle, x, y - 10);
            // Console.WriteLine(e.KeyValue.ToString());
            switch (e.KeyCode)
            {
                case Keys.ControlKey:
                    CtrlDown = true;
                    break;
            }

            base.OnKeyDown(e);

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnKeyUp(KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.ControlKey:
                    CtrlDown = false;
                    break;
            }
            base.OnKeyUp(e);
        }


        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            base.OnKeyPress(e);
        }
        protected override void OnControlAdded(ControlEventArgs e)
        {
            base.OnControlAdded(e);
        }

        /// <summary>
        /// 控件创建的时候执行
        /// </summary>
        protected override void InitLayout()
        {
            base.OnCreateControl();
            OnLoad();
            TerminalOnLoaded?.Invoke(this);
        }

        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);
            // Log.Debug("Terminal", "OnGotFocus");
            IsFocused = true;

            InvalidatePaint();

            // User32.CreateCaret(Handle,0,fontSize.Width,fontSize.Height);
            // User32.ShowCaret(Handle);
        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
            if (Closed)
                return;
            Log.Debug("Terminal", "OnLostFocus 失去焦点");
            IsFocused = false;

            //User32.DestroyCaret();

            InvalidatePaint();

        }

        public bool ShowCursor()
        {

            return cursorVisible &&
                container.CurrentLineAdsIndex >= screenLineStart &&
                container.CurrentLineAdsIndex < screenLineStart + displayRows &&
                container.CursorIndex < displayColumns;
        }

        protected Point PixelsToTerPoint(int x, int y)
        {
            int sc = screenLineStart;
            Point point = new Point();
            point.X = (x - GetTextOffsetLeft()) / fontSize.Width;
            point.Y = ((y - GetTextOffsetTop()) / fontSize.Height + sc);

            if (point.X < 0)
                point.X = 0;
            else if (point.X > GetDisplayColumns() - 1)
                point.X = GetDisplayColumns() - 1;

            if (point.Y < sc)
            {
                point.Y = Math.Max(point.Y, 0);
                point.X = 0;
            }
            else if (point.Y >= sc + GetDisplayRows())
            {
                point.Y = Math.Min(point.Y, container.Count - 1);
                point.X = GetDisplayColumns() - 1;
            }

            return point;
        }

        public new bool CanFocus
        {
            get
            {
                return true;
            }
        }
        public new bool CanSelect
        {
            get
            {
                return true;
            }
        }

        private void OnMouseReportEvent(int keycode, int x, int y)
        {
            OnMouseReport?.Invoke(keycode + 32, x + 1 + 32, y + 1 + 32);
        }

        /// <summary>
        /// 鼠标按键按下时触发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            Capture = true;
            if (!IsFocused)
                Focus();

            mousePoint.X = e.X;
            mousePoint.Y = e.Y;
            mouseDown = false;
            if (this.mouseReport)
            {
                Point point = PixelsToTerPoint(mousePoint.X, mousePoint.Y);
                switch (e.Button)
                {
                    case MouseButtons.Left:
                        OnMouseReportEvent(0, point.X, point.Y);
                        break;
                    case MouseButtons.Middle:
                        OnMouseReportEvent(1, point.X, point.Y);
                        break;
                    case MouseButtons.Right:
                        OnMouseReportEvent(2, point.X, point.Y);
                        break;
                }
            }
            else
            {

                if (e.Button == MouseButtons.Left)
                {
                    mouseDown = true;
                    if (onMouseDoubleClick)
                    {
                        selectRegion.StartX = 0;
                        selectRegion.EndX = displayColumns - 1;
                        onMouseDoubleClick = false;
                        mouseClickTimer.Stop();
                        container.InvalidAbs(selectRegion.StartY, 1);
                        InvalidatePaint();
                    }
                    else
                    {
                        /*
                         * 如果存在选取则单击后取消选取并且更新相关区域
                         */
                        //Log.Debug("Terminal", "OnMouseDown");

                        ClearSelectRegion();

                        Point point = PixelsToTerPoint(mousePoint.X, mousePoint.Y);
                        mouseDownColumns = point.X;
                        mouseDownRows = point.Y;
                    }

                }

                base.OnMouseDown(e);

            }
        }
        /// <summary>
        /// 鼠标按键松开时触发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e)
        {

            base.OnMouseUp(e);
            mouseDown = false;
            if (this.mouseReport)
            {
                Point point = PixelsToTerPoint(e.X, e.Y);
                OnMouseReportEvent(3, point.X, point.Y);
            }
            else
            {
                if (e.Button == MouseButtons.Left)
                {
                    mouseDown = false;
                }
            }
        }

        private void UpdateSelectRegion()
        {
            if (selectRegion.updateStartY > -1 && selectRegion.updateEndY >= screenLineStart)
            {
                int start = Math.Max(screenLineStart, selectRegion.updateStartY);
                int len = selectRegion.updateEndY - start + 1;
                container.InvalidAbs(start, len);
                InvalidatePaint();
            }
        }

        /// <summary>
        /// 清除选区
        /// </summary>
        private void ClearSelectRegion()
        {
            if (!selectRegion.Enable)
                return;
            int startY = Math.Max(selectRegion.StartY, screenLineStart);
            int len = selectRegion.EndY - startY + 1; ;
            selectRegion.Reset();
            container.InvalidAbs(startY, len);
            InvalidatePaint();
            //PaintEvent(TEvent.Paint, startY, endY - startY + 1);
        }

        /// <summary>
        /// 鼠标双击时触发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            base.OnMouseDoubleClick(e);
            if (!this.mouseReport)
            {
                if (e.Button == MouseButtons.Left)
                {
                    Point point = PixelsToTerPoint(e.X, e.Y);
                    int columns = point.X;
                    int rows = point.Y;
                    Line line = container[rows];
                    int lineCharCount = line.Characters.Count;

                    if (lineCharCount == 0)
                    {
                        return;
                    }
                    if (columns > lineCharCount - 1)
                    {
                        columns = lineCharCount - 1;
                    }
                    char[] sp = Preference.Default.Terminal_SplitChar.ToCharArray();
                    int start = columns;
                    int end = columns;
                    if (Array.IndexOf(sp, line[columns].c) == -1)
                    {
                        for (int i = columns - 1; i >= 0; i--)
                        {
                            if (Array.IndexOf(sp, line[i].c) > -1 && (line[i].mask & 0x04) != 0x04)
                            {
                                break;
                            }
                            start = i;
                        }
                        for (int i = columns + 1; i < lineCharCount; i++)
                        {
                            if (Array.IndexOf(sp, line[i].c) > -1 && (line[i].mask & 0x04) != 0x04)
                            {
                                break;
                            }
                            end = i;
                        }
                    }

                    ClearSelectRegion();


                    selectRegion.StartY = rows;
                    selectRegion.EndY = rows;
                    selectRegion.StartX = start;
                    selectRegion.EndX = end;
                    selectRegion.Enable = true;


                    mouseClickTimer.Start();
                    onMouseDoubleClick = true;
                    container.InvalidAbs(rows, 1);
                    InvalidatePaint();
                    //PaintEvent(TEvent.Paint, rows - ScreenLineStart, 1);
                }
            }
        }


        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
        }

        /// <summary>
        /// 执行鼠标移动的方法，主要用于绘制选区
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void OnMouseMove(int x, int y)
        {

            int startX;
            int endX;
            int startY;
            int endY;

            Point point = PixelsToTerPoint(x, y);
            int columns = point.X;
            int rows = point.Y;
            //向上滑动鼠标
            if (mouseDownRows > rows)
            {
                startY = rows;
                endY = this.mouseDownRows;
                startX = columns;
                endX = this.mouseDownColumns;
            }
            //向下滑动鼠标
            else if (mouseDownRows < rows)
            {
                startY = this.mouseDownRows;
                endY = rows;
                startX = this.mouseDownColumns;
                endX = columns;
            }
            else
            {
                startY = rows;
                endY = rows;
                if (columns < this.mouseDownColumns)
                {
                    startX = columns;
                    endX = mouseDownColumns;
                }
                else
                {
                    startX = mouseDownColumns;
                    endX = columns;
                }
            }

            if (startY < 0)
                return;

            // else if(selectRegion.endY > )
            if (container[startY].Characters.Count <= startX)
            {
                startX = container[startY].Characters.Count;
            }
            else
            {
                if (container[startY][startX].TestMask(CharacterMask.Half2))
                    startX--;
            }
            if (container[endY].Characters.Count <= endX)
            {
                endX = GetDisplayColumns() - 1;
            }
            else
            {
                if (container[endY][endX].TestMask(CharacterMask.Half1))
                    endX++;
            }

            //计算失效范围
            if (selectRegion.StartY == -1 || selectRegion.EndY == -1)
            {
                selectRegion.updateStartY = startY;
                selectRegion.updateEndY = endY;
            }
            else if (startY != selectRegion.StartY && endY != selectRegion.EndY)
            {
                selectRegion.updateStartY = Math.Min(startY, selectRegion.StartY);
                selectRegion.updateEndY = Math.Max(endY, selectRegion.EndY);
            }
            else if (startY != selectRegion.StartY)
            {
                selectRegion.updateStartY = Math.Min(startY, selectRegion.StartY);
                selectRegion.updateEndY = Math.Max(startY, selectRegion.StartY);
            }
            else if (endY != selectRegion.EndY)
            {
                selectRegion.updateStartY = Math.Min(endY, selectRegion.EndY);
                selectRegion.updateEndY = Math.Max(endY, selectRegion.EndY);
            }
            else if (startX != selectRegion.StartX || endX != selectRegion.EndX)
            {
                selectRegion.updateStartY = rows;
                selectRegion.updateEndY = rows;
            }
            else
            {
                selectRegion.updateStartY = -1;
                selectRegion.updateEndY = -1;
            }


            selectRegion.Enable = true;
            selectRegion.StartY = startY;
            selectRegion.EndY = endY;
            selectRegion.StartX = startX;
            selectRegion.EndX = endX;

        }

        private void MouseMoveLeaveTimer()
        {
            if (point.Y < 0)
            {
                if (ScreenLineStart > 0 || mouseHasMove)
                {
                    OnMouseMove(point.X, point.Y);
                    UpdateSelectRegion();

                    ScrollTo(selectRegion.StartY);
                    UpdateScrollBar();
                    InvalidatePaint();
                    mouseHasMove = false;
                }

            }
            else if (point.Y > Height)
            {
                if (ScreenLineStart < container.ConsoleOffset || mouseHasMove)
                {
                    OnMouseMove(point.X, point.Y);
                    UpdateSelectRegion();

                    ScrollTo(selectRegion.EndY - container.Height + 1);
                    UpdateScrollBar();
                    InvalidatePaint();
                    mouseHasMove = false;
                }

            }
        }
        private void MouseMoveLeaveTimer(object sender, ElapsedEventArgs e)
        {
            Invoke((EventHandler)delegate
            {
                MouseMoveLeaveTimer();
            });
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            mouseMoveLeaveTimer.Enabled = false;
        }
        /// <summary>
        /// 鼠标移动时触发
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (this.mouseDown)
            {
                if (Math.Abs(mousePoint.X - e.X) < fontSize.Width / 2
                    &&
                    Math.Abs(mousePoint.Y - e.Y) < fontSize.Height / 2)
                {
                    return;
                }
                int x = e.X;
                int y = e.Y;
                if (y < 0 || y > Height)
                {
                    mouseHasMove = true;
                    point.X = x;
                    point.Y = y;

                    MouseMoveLeaveTimer();
                    if (mouseMoveLeaveTimer.Enabled == false)
                    {
                        // 允许Timer执行
                        mouseMoveLeaveTimer.Enabled = true;
                    }
                    return;
                }
                else
                {
                    if (mouseMoveLeaveTimer.Enabled)
                    {
                        mouseMoveLeaveTimer.Enabled = false;
                    }
                }

                //如果更新区域为负数则说明没有更新
                //那就不发送绘制消
                OnMouseMove(x, y);
                UpdateSelectRegion();

            }
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
        }


        /// <summary>
        /// 
        /// </summary>
        public void OnLoad()
        {

        }


        // public override 

        public void DoStyleChanged()
        {
            OnStyleChanged();
            InvalidatePaint();
        }

        public void ScrollTo(int newValue)
        {
            //int oldValue = screenLineStart;
            //screenLineStart = newValue;
            ScrollTo(screenLineStart, newValue);
        }

        /// <summary>
        /// 滚动内容
        /// </summary>
        /// <param name="oldValue"></param>
        /// <param name="newValue"></param>
        /// <param name="darwToScreen"></param>
        ///

        protected virtual void ScrollTo(int oldValue, int newValue)
        {
            int scrollValue = newValue - oldValue;
            scrollingLines += scrollValue;
            screenLineStart = newValue;

        }

        public int GetDisplayRows()
        {
            return this.displayRows;
        }

        public int GetDisplayColumns()
        {
            return this.displayColumns;
        }

        public int GetTextOffsetLeft()
        {
            return 5;
        }
        public int GetTextOffsetTop()
        {
            return 5;
        }

        public int GetWorkWidth()
        {
            return Width - 5 - scrollBar.Width;
        }


        public int GetWorkHeight()
        {
            return Height - 10;
        }



        protected override void OnControlRemoved(ControlEventArgs e)
        {
            base.OnControlRemoved(e);
        }

        void ISupportInitialize.BeginInit()
        {
            Initialize = true;
        }

        void ISupportInitialize.EndInit()
        {
            Initialize = false;
            InvalidatePaint();
        }

        public class TLog : ITerminalLog
        {
            StreamWriter streamWriter = null;
            string path;
            public override void Close()
            {
                if (streamWriter != null)
                {
                    streamWriter.Close();
                    streamWriter.Dispose();
                    streamWriter = null;
                }
            }

            public override void Open(string path)
            {
                if (streamWriter != null)
                    return;
                this.path = path;
                streamWriter = new StreamWriter(path, true);
            }

            public override void Write(string text)
            {
                streamWriter.WriteLine(text);
                streamWriter.Flush();
            }
        }



    }


}
